package hehe.container.definition;

import hehe.container.format.DataFormat;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 类的反射对象
 *<B>说明：</B>
 *<pre>
 * 收集类对应的属性
 *</pre>
 *<B>示例：</B>
 *<pre>
 *  略
 *</pre>
 *<B>日志：</B>
 *<pre>
 *  略
 *</pre>
 *<B>注意事项：</B>
 *<pre>
 *  略
 *</pre>
 */
public class Reflection
{
    /**
     * 目标Class
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param clazz
     */
    private Class targetClazz = null;

    /**
     * 构造方法的参数列表
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param clazz
     */
    private List<Map<String,String>> params = new ArrayList<>();

    /**
     * 类属性，包括父类属性
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param clazz
     */
    protected Map<String,Field> attributes = new HashMap<>();


    public Reflection() {}

    /**
     * 构造方法
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param clazz
     */
    public Reflection(Class clazz)
    {
        this.targetClazz = clazz;
    }

    /**
     * 获取所有父类包括自己
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param targetClass
     */
    public List<Class> findSuperClass(Class targetClass)
    {
        List<Class> superClasss = new ArrayList<>();
        superClasss.add(targetClass);

        while (true) {//当父类为null的时候说明到达了最上层的父类(Object类).
            targetClass = targetClass.getSuperclass(); //得到父类,然后赋给自己
            if (targetClass != null && !targetClass.getSimpleName().equals("Object")) {
                superClasss.add(targetClass);
            } else {
                break;
            }
        }

        return superClasss;
    }

    /**
     * 获取类定义的属性对象
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param clazz class 对象
     * @param attrName 属性名
     */
    public Field getDeclaredField(Class clazz, String attrName)
    {

        Field field = null ;

        try {
            field = clazz.getDeclaredField(attrName) ;
            return field ;
        } catch (Exception e) {
            // 找不到属性
            return null;
        }
    }

    /**
     * 获取类属性对象
     *<B>说明：</B>
     *<pre>
     *  包括private,public,protected 属性
     *</pre>
     * @param fieldName 属性名
     * @return 属性对象
     */
    public Field getField(String fieldName)
    {
        return this.getField(this.targetClazz,fieldName);
    }

    /**
     * 获取类属性对象
     *<B>说明：</B>
     *<pre>
     *  包括private,public,protected 属性
     *</pre>
     * @param clazz class 对象
     * @param fieldName 属性名
     * @return 属性对象
     */
    public Field getField(Class clazz,String fieldName)
    {

        // 读取缓存
        if (this.attributes.containsKey(fieldName)) {
            return this.attributes.get(fieldName);
        }

        // 读取所有父类及本来
        List<Class> superClazzs = this.findSuperClass(clazz);
        Field field = null ;

        for (int i = 0;i < superClazzs.size();i++)  {
            field = this.getDeclaredField(superClazzs.get(i),fieldName);
            if (field != null) {
                // 找到属性,保持至至缓存
                this.attributes.put(fieldName,field);
                break;
            }
        }

        return field;
    }

    /**
     * 设置对象属性值
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param attrs 对象
     * @param object 属性名
     */
    public void setAttrs(Map<String,Object> attrs,Object object)
    {
        Class targetClazz = object.getClass();

        for (Map.Entry<String, Object> attr : attrs.entrySet()) {
            try {
                Field field = this.getField(targetClazz,attr.getKey());
                if (field != null) {
                    field.setAccessible(true);
                    // value类型转换
                    Object value = DataFormat.invoke(field.getType().getTypeName(),attr.getValue(),field);
                    field.set(object,value);
                }
            } catch (Exception e) {
                // 不做任何事情
                e.printStackTrace();
            }
        }
    }

    /**
     * 创建对象
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return Object
     */
    public Object make() throws Exception
    {
        try {
            // 获取构造方法
            return this.targetClazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("class className make fail");
        }
    }

    /**
     * 创建对象
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param args 构造方法参数
     * @return Object
     */
    public Object make(Object[] args) throws Exception
    {
        try {

            Class[] argsClass = new Class[args.length];
            for (int i = 0, j = args.length; i < j; i++) {
                argsClass[i] = args[i].getClass();
            }

            // 获取构造方法
            Constructor constructor = this.targetClazz.getDeclaredConstructor(argsClass);

            return constructor.newInstance(args);
        } catch (Exception e) {
            throw new Exception("class className make fail");
        }
    }

    /**
     * 获取对象属性对象
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param attrs 构造方法参数
     * @return Object
     */
    public Map<String,Field> getFields(String[] attrs)
    {
        Map<String,Field> fields = new HashMap<>();
        Field field = null;
        for (int i = 0,j = attrs.length;i < j;i++) {
            field = this.getField(attrs[i]);
            if (field != null) {
                fields.put(attrs[i],field);
            }
        }

        return fields;
    }

    /**
     * 初始化init 方法
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public void invoke(String methodName,Object target)
    {
        try {
            Method method = this.targetClazz.getDeclaredMethod(methodName, (Class<?>[]) null);
            method.invoke(target,(Object[]) null);
        } catch (NoSuchMethodException ex) {

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


}
